//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package issue_dao

import (
	"context"
	"fmt"

	"atomgit.com/openlinksaas/api-server/dao/db_ns"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_issue_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type BasicVoteInfoDbItem struct {
	EstimateMinutes uint32 `bson:"estimateMinutes"`
	Important       bool   `bson:"important"`
	Urgency         bool   `bson:"urgency"`
	ExtraDesc       string `bson:"extraDesc"`
}

type VoteInfoDbItem struct {
	VoteId     string              `bson:"_id"` //自动生成
	IssueId    string              `bson:"issueId"`
	BasicInfo  BasicVoteInfoDbItem `bson:"basicInfo"`
	TimeStamp  int64               `bson:"timeStamp"`
	VoteUserId string              `bson:"voteUserId"`
}

func (item *VoteInfoDbItem) ToVoteInfo() *project_issue_api.VoteInfo {
	return &project_issue_api.VoteInfo{
		VoteId: item.VoteId,
		BasicInfo: &project_issue_api.BasicVoteInfo{
			EstimateMinutes: item.BasicInfo.EstimateMinutes,
			Important:       item.BasicInfo.Important,
			Urgency:         item.BasicInfo.Urgency,
			ExtraDesc:       item.BasicInfo.ExtraDesc,
		},
		TimeStamp:  item.TimeStamp,
		VoteUserId: item.VoteUserId,
	}
}

type _VoteDao struct {
	mc *mongo.Collection
}

func newVoteDao(db *mongo.Database) (*_VoteDao, error) {
	mc := db.Collection(db_ns.DB_NS_ISSUE + "vote")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"issueId", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_VoteDao{mc: mc}, nil
}

func (db *_VoteDao) Upsert(ctx context.Context, dbItem *VoteInfoDbItem) error {
	dbItem.VoteId = db.genVoteId(dbItem.IssueId, dbItem.VoteUserId)
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": dbItem.VoteId, "issueId": dbItem.IssueId},
		bson.M{"$set": dbItem}, options.Update().SetUpsert(true))
	return err
}

func (db *_VoteDao) genVoteId(issueId, voteUserId string) string {
	return fmt.Sprintf("%s:%s", issueId, voteUserId)
}

func (db *_VoteDao) Exist(ctx context.Context, issueId, voteUserId string) (bool, error) {
	voteId := db.genVoteId(issueId, voteUserId)
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": voteId, "issueId": issueId})
	return count > 0, err
}

func (db *_VoteDao) Get(ctx context.Context, issueId, voteUserId string) (*VoteInfoDbItem, error) {
	voteId := db.genVoteId(issueId, voteUserId)
	retItem := &VoteInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": voteId, "issueId": issueId}).Decode(retItem)
	return retItem, err
}

func (db *_VoteDao) Remove(ctx context.Context, issueId, voteUserId string) error {
	voteId := db.genVoteId(issueId, voteUserId)
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": voteId, "issueId": issueId})
	return err
}

func (db *_VoteDao) RemoveByIssue(ctx context.Context, issueId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"issueId": issueId})
	return err
}

func (db *_VoteDao) List(ctx context.Context, issueId string) ([]*VoteInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"issueId": issueId}, options.Find().SetSort(bson.M{"timeStamp": 1}))
	if err != nil {
		return nil, err
	}
	retList := []*VoteInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}
